package org.apache.ibatis.config.mapping;

import org.apache.ibatis.common.annotations.ResultType;
import org.apache.ibatis.common.type.JdbcType;
import org.apache.ibatis.common.type.TypeHandler;
import org.apache.ibatis.common.type.TypeHandlerRegistry;
import org.apache.ibatis.sql.cache.Cache;
import org.apache.ibatis.sql.session.Configuration;

/**
 * @Name ParameterMapping
 * @Description: [参数映射] 类
 * SQL 语句中的参数列表 #{} 应该是这样的：
 * #{ property = id, javaType = int, jdbcType = NUMERIC, typeHandler = DemoTypeHandler }
 * 描述信息：该类就是用来存储以上的参数列表内容的。
 * 提示：大多数情况下，只有 property = id 这一项，其他的会被推测出来，而不是被指定。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-19 16:28:10
 **/
public class ParameterMapping {
    private Configuration config;
    // 参数名称（标识）
    private String property;
    // 参数模式（输入、输出、输入输出），主要用于存储过程
    private ParameterMode mode;
    // 参数的 JAVA 类型
    private Class<?> javaType = Object.class;
    // 参数的 JDBC 类型
    private JdbcType jdbcType;
    // JDBC 类型属性值
    private String jdbcTypeName;
    // 数值精度
    private Integer numericScale;
    // 类型处理器
    private TypeHandler<?> typeHandler;
    // 参数模式为输出、输入输出时，对应的 ResultMap 结果集
    private String resultMapId;
    // 扩展字段
    private String expression;

    public static class Builder {
        private ParameterMapping parameterMapping = new ParameterMapping();

        public Builder(Configuration config, String property, TypeHandler<?> typeHandler) {
            parameterMapping.config = config;
            parameterMapping.property = property;
            parameterMapping.typeHandler = typeHandler;
            parameterMapping.mode = ParameterMode.IN;
        }

        public Builder(Configuration config, String property, Class<?> javaType) {
            parameterMapping.config = config;
            parameterMapping.property = property;
            parameterMapping.javaType = javaType;
            parameterMapping.mode = ParameterMode.IN;
        }

        public Builder mode(ParameterMode mode) {
            parameterMapping.mode = mode;
            return this;
        }

        public Builder javaType(Class<?> javaType) {
            parameterMapping.javaType = javaType;
            return this;
        }

        public Builder jdbcType(JdbcType jdbcType) {
            parameterMapping.jdbcType = jdbcType;
            return this;
        }

        public Builder jdbcTypeName(String jdbcTypeName) {
            parameterMapping.jdbcTypeName = jdbcTypeName;
            return this;
        }

        public Builder numericScale(Integer numericScale) {
            parameterMapping.numericScale = numericScale;
            return this;
        }

        public Builder typeHandler(TypeHandler<?> typeHandler) {
            parameterMapping.typeHandler = typeHandler;
            return this;
        }

        public Builder resultMapId(String resultMapId) {
            parameterMapping.resultMapId = resultMapId;
            return this;
        }

        public Builder expression(String expression) {
            parameterMapping.expression = expression;
            return this;
        }

        public ParameterMapping build() {
            resolveTypeHandler();
            validate();
            return parameterMapping;
        }

        private void resolveTypeHandler() {
            if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) {
                Configuration config = parameterMapping.config;
                TypeHandlerRegistry typeHandlerRegistry = config.getTypeHandlerRegistry();
                parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, parameterMapping.jdbcType);
            }
        }

        private void validate() {
            if (ResultType.class.equals(parameterMapping.javaType)) {
                if (parameterMapping.resultMapId == null) {
                    String msg = "属性 '" + parameterMapping.property + "' 中缺少 ResultMap。类型为 java.sql.ResultSet 的参数需要一个 ResultMap 结果映射。";
                    throw new IllegalStateException(msg);
                }
            } else {
                if (parameterMapping.typeHandler == null) {
                    String msg = "在属性 '" + parameterMapping.property + "' 的参数映射上，TypeHandler 类型处理程序为 null。没有为 JavaType:JdbcType [" + parameterMapping.javaType + ":" + parameterMapping.jdbcTypeName + "] 组合指定 TypeHandler 类型处理程序。";
                    throw new IllegalStateException(msg);
                }
            }
        }

    }

    public String getProperty() {
        return property;
    }

    public ParameterMode getMode() {
        return mode;
    }

    public Class<?> getJavaType() {
        return javaType;
    }

    public JdbcType getJdbcType() {
        return jdbcType;
    }

    public String getJdbcTypeName() {
        return jdbcTypeName;
    }

    public Integer getNumericScale() {
        return numericScale;
    }

    public TypeHandler<?> getTypeHandler() {
        return typeHandler;
    }

    public String getResultMapId() {
        return resultMapId;
    }

    public String getExpression() {
        return expression;
    }

    @Override
    public String toString() {
        return "ParameterMapping{" +
                "property='" + property + '\'' +
                ", mode=" + mode +
                ", javaType=" + javaType +
                ", jdbcType=" + jdbcType +
                ", jdbcTypeName='" + jdbcTypeName + '\'' +
                ", numericScale=" + numericScale +
                ", resultMapId='" + resultMapId + '\'' +
                ", expression='" + expression + '\'' +
                '}';
    }
}

